package com.bonc.event.eventtype;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;

import com.bonc.utilities.EventUtility;
import com.bonc.vectorspace.model.Document;
import com.bonc.vectorspace.model.EventCorpus;
import com.bonc.vectorspace.model.EventDocument;
import com.bonc.vectorspace.model.VectorSpaceModel;

import cc.mallet.classify.Classifier;
import cc.mallet.classify.ClassifierTrainer;
import cc.mallet.classify.MaxEnt;
import cc.mallet.classify.MaxEntTrainer;
import cc.mallet.types.Alphabet;
import cc.mallet.types.FeatureVector;
import cc.mallet.types.Instance;
import cc.mallet.types.InstanceList;
import cc.mallet.types.Label;
import cc.mallet.types.LabelAlphabet;
import cc.mallet.types.Labeling;

/**
 * @author donggui@bonc.com.cn
 * @version 2016 2016年7月1日 上午11:51:07
 */
public class EventTypeTrainer {
	
	private Set<String> featureTerms;
	
	private Classifier classifier;	
	
	private EventCorpus trainingCorpus;
	
	public EventCorpus getTrainingCorpus() {
		return trainingCorpus;
	}

	private static Map<String,String> stopwords = EventUtility.loadStopwords();
	
	@Autowired
	EventTypeFeatureExtractor eventTypeFeatureExtractor;
	
	public EventTypeTrainer(){
		if(eventTypeFeatureExtractor == null){
			eventTypeFeatureExtractor = new EventTypeFeatureExtractor();
		}
	}
	
	public void TrainEventType(String trainingDirname, String modelFileName){
		HashMap<String, String> texttags = EventUtility.convertFiles2Text(trainingDirname);
		Iterator<Map.Entry<String, String>> iter = texttags.entrySet().iterator();
		List<EventDocument> documents = new ArrayList<EventDocument>();
		int k = 0;
		while(iter.hasNext()){
			Map.Entry entry = (Map.Entry) iter.next();
			Object content = entry.getKey();
			Object tag = entry.getValue();
			if(content!=null && !"".equals(content.toString().trim())){
				System.out.println("======1111"+content.toString());
//				String featureText = eventTypeFeatureExtractor.extract2String(content.toString());
				String featureText = content.toString();
				if(featureText !=null && !"".equals(featureText.trim())){
					System.out.println("featureText=="+featureText);
					String docId = tag.toString() + k;
					EventDocument document = new EventDocument(docId, featureText,tag.toString(),stopwords);
					if(document!=null){
						documents.add(document);
					}
				}

			}
		}
		if(documents!=null){
				
			try {
				trainingCorpus = new EventCorpus(documents);
				File modelFile = new File(modelFileName);

				classifier = this.TrainEventType(trainingCorpus, modelFile);
				
//				return classifier;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
//		return null;

	}
	
//	private String convertText2Feature(String text){
////		String result = "";
//		if(text!=null){
//			String features = eventTypeFeatureExtractor.extract(text);
//			return features;
//		}
		
//		System.out.println("test=============");
//		for(String feature:features){
//			result += feature + '\t';
//		}
//		return null;
//	}
	
	public Classifier TrainEventType(EventCorpus trainingCorpus, File modelFile) throws FileNotFoundException, IOException{
		VectorSpaceModel vectorSpace = new VectorSpaceModel(trainingCorpus);
		
		//maxent
        Alphabet featureAlphabet = new Alphabet();//特征词典
        LabelAlphabet targetAlphabet = new LabelAlphabet();//类标词典
        
        Set<String> labels = trainingCorpus.getTags();
        for(String label:labels){
        	targetAlphabet.lookupIndex(label);
        }
        targetAlphabet.stopGrowth();
        
        this.setFeatureTerms(trainingCorpus.getInvertedIndex().keySet());
        for (String term : featureTerms) {
        	featureAlphabet.lookupIndex(term);	       	
        }

        InstanceList allInstances = new InstanceList (featureAlphabet,targetAlphabet);//实例集对象
        int featuresize = featureTerms.size();

        System.out.println("test TrainEventType =======");
        for (EventDocument document : trainingCorpus.getDocuments()) {
        	
        	HashMap<String, Double> weights = vectorSpace.getTfIdfWeights().get(document);
        	
        	double[] featureValues1 = new double[featuresize];
        	int j = 0;
        	for (String term : featureTerms) {		
				Double weight = weights.get(term);
				if(weight !=null ){
					featureValues1[j] = weight.doubleValue();
				}else{
					featureValues1[j] = 0.0;
				}
				j++;
//        		double frequency = document.getTermFrequency(term);				
//        		featureValues1[j] = frequency;j++;				
        	}
        	System.out.println();			

        	FeatureVector featureVector = new FeatureVector(featureAlphabet,featureTerms.toArray(new String[featuresize]),featureValues1);//change list to array           
        	System.out.println("test1=="+document.getTag());
        	Instance instance = new Instance (featureVector,targetAlphabet.lookupLabel(document.getTag()), document.getDocId(),null);
        	//             Instance instance = new Instance (featureVector,targetAlphabet.lookupLabel(targetValue.get(i)), document.getFileName(),null);

        	allInstances.add(instance);
        }

		long startTime = System.currentTimeMillis();
		PrintStream temp = System.err;
		System.setErr(System.out);
		
		double Gaussian_Variance = 1.0;
		ClassifierTrainer<MaxEnt> trainer = new MaxEntTrainer(Gaussian_Variance);		
		Classifier classifier = trainer.train(allInstances); 
		
		System.setErr(temp);
		// calculate running time
		long endTime = System.currentTimeMillis();
		long totalTime = endTime - startTime;
		System.out.println("Total training time: " + totalTime);
		
		// write model
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(modelFile));
	    oos.writeObject(classifier);
	    oos.close();
	    
		return classifier;		
	}
	
    //predict & evaluate
    public static String predict(Classifier myClassifier,Instance testInstance){
        Labeling labeling = myClassifier.classify(testInstance).getLabeling();
        Label label = labeling.getBestLabel();
        System.out.println(labeling.toString());
        return (String)label.getEntry();
    }
    
    public Labeling predict(Instance testInstance){
        Labeling labeling = classifier.classify(testInstance).getLabeling();
//        Label label = labeling.getBestLabel();
//        return (String)label.getEntry();
        return labeling;
    }
    

	public Set<String> getFeatureTerms() {
		return featureTerms;
	}

	public void setFeatureTerms(Set<String> featureTerms) {
		this.featureTerms = featureTerms;
	}

	public Classifier getClassifier() {
		return classifier;
	}	

}
